

/**
 * Primitive对象基类
 */
import { v4 as uuid } from 'uuid'
import PrimitiveEvent from '../event/types/PrimitiveEvent'

export default class Primitive {
  constructor() {
    this._id = uuid()
    this._show = true
    this._attr = {}
    this.delegate = undefined
    this._style = undefined
    this._type = undefined
    this._layer = undefined

    this._modelMatrix = undefined
    // 模型旋转相关
    this._heading = 0
    this._pitch = 0
    this._roll = 0
    this._rotateAmount = 0

    this._timer = null
    this._primitiveEvent = new PrimitiveEvent()
  }

  /**
  * 
  * @param {Number} angle 设置旋转角度 
  */
  startRotate(angle = 1) {
    this._rotateAmount = angle

    this._timer = setInterval(() => {
      this._heading += this._rotateAmount
      if (this._heading >= 360 || this._heading <= -360) {
        this._heading = 0
      }
      this.modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
        this._positions,
        new Cesium.HeadingPitchRoll(
          Cesium.Math.toRadians(this._heading),
          Cesium.Math.toRadians(this._pitch),
          Cesium.Math.toRadians(this._roll)
        ),
        Cesium.Ellipsoid.WGS84,
        Cesium.Transforms.eastNorthUpToFixedFrame,
        new Cesium.Matrix4()
      )
    }, 1000 / 60)
  }
  /**
  * 停止旋转
  */
  stopRotate() {
    if (this.timer) {
      clearInterval(this.timer)
      this.timer = null
    }
  }

  /**
   * 模型角度更改 自动设置朝向
   */
  setRotate() {
    this.modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
      this._positions,
      new Cesium.HeadingPitchRoll(
        Cesium.Math.toRadians(this._heading),
        Cesium.Math.toRadians(this._pitch),
        Cesium.Math.toRadians(this._roll)
      ),
      Cesium.Ellipsoid.WGS84,
      Cesium.Transforms.eastNorthUpToFixedFrame,
      new Cesium.Matrix4()
    )
  }

  /**
   * 设置位置
   */
  setPosition() {
    this.modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
      this._positions,
      new Cesium.HeadingPitchRoll(
        Cesium.Math.toRadians(this._heading),
        Cesium.Math.toRadians(this._pitch),
        Cesium.Math.toRadians(this._roll)
      ),
      Cesium.Ellipsoid.WGS84,
      Cesium.Transforms.eastNorthUpToFixedFrame,
      new Cesium.Matrix4()
    )
  }

  /**
   * 设置材质
   * @returns 
   */
  setAppearance(MaterialOption, options = {}) {
    if (!MaterialOption) return

    let type = MaterialOption.type
    delete MaterialOption.type
    this.delegate.appearance = new Cesium.MaterialAppearance({
      material: Cesium.Material.fromType(type, {
        ...MaterialOption
      }),
      ...options
    })
  }

  /**
   * 设置图片材质
   * @param {*} image 图片地址
   */
  setImage(options = {}) {
    if (!options) return
    this.delegate.appearance = new Cesium.MaterialAppearance({
      material: Cesium.Material.fromType('Image', {
        ...options
      })
    })
  }

  /**
   * 绑定图元事件
   */
  on(type, fn) {
    this._primitiveEvent.on(type, fn)
  }

  /**
   * 删除事件
   */
  off(type, fn) {
    this._primitiveEvent.off(type, fn)
  }

  /**
   * 当primitive被添加到layer图层时 为其增加所有的事件
   */
  
  emit() {
    this._primitiveEvent._setInputaction(this)
  }


  get id() {
    return this._id
  }

  get style() {
    return this._style
  }

  set style(val) {
    this._style = val
    this.setStyle(this._style)
  }

  get layer() {
    return this._layer
  }

  get attr() {
    return this._attr
  }

  set attr(val) {
    this._attr = val
  }

  get show() {
    return this._show
  }

  set show(val) {
    this._show = val
    this.delegate.show = this._show
  }

  get type() {
    return this._type
  }

  get heading() {
    return this._heading
  }

  set heading(val) {
    this._heading = val
    this.setRotate()
  }

  get pitch() {
    return this._pitch
  }

  set pitch(val) {
    this._pitch = val
    this.setRotate()
  }

  get roll() {
    return this._roll
  }

  set roll(val) {
    this._roll = val
    this.setRotate()
  }

  get rotateAmount() {
    return this._rotateAmount
  }

  set rotateAmount(val) {
    this._rotateAmount = val
  }

  get timer() {
    return this._timer
  }

  set timer(val) {
    this._timer = val
  }


  get modelMatrix() {
    this._modelMatrix = this.delegate.modelMatrix
    return this._modelMatrix
  }

  /**
   * 从矩阵更新位置和角度
   */
  set modelMatrix(val) {
    this._modelMatrix = val
    this.delegate.modelMatrix = this._modelMatrix
    let x = this._modelMatrix[12]
    let y = this._modelMatrix[13]
    let z = this._modelMatrix[14]
    let position = new Cesium.Cartesian3(x, y, z)
    // 计算旋转角度
    let modelMatrix = this.modelMatrix
    let orientation = new Cesium.Quaternion()
    // 计算中心处的变换矩阵
    var m1 = Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Matrix4.getTranslation(modelMatrix, new Cesium.Cartesian3()), Cesium.Ellipsoid.WGS84, new Cesium.Matrix4());
    // 矩阵相相乘
    var m3 = Cesium.Matrix4.multiply(Cesium.Matrix4.inverse(m1, new Cesium.Matrix4()), modelMatrix, new Cesium.Matrix4())
    // 获取3乘3矩阵
    m3 = Cesium.Matrix4.getMatrix3(m3, new Cesium.Matrix3())
    // 获取旋转矩阵
    let rotation = Cesium.Matrix3.getRotation(m3, new Cesium.Matrix3())
    // 从旋转矩阵计算四元数
    orientation = Cesium.Quaternion.fromRotationMatrix(rotation, orientation)
    // 计算角度
    var hpr = Cesium.HeadingPitchRoll.fromQuaternion(orientation)

    // 同步更新模型位置
    this._positions = position
    // 转换
    this._heading = Cesium.Math.toDegrees(hpr.heading)
    this._pitch = Cesium.Math.toDegrees(hpr.pitch)
    this._roll = Cesium.Math.toDegrees(hpr.roll)
  }
}
